// import com.alibaba.druid.sql.ast.SQLExpr;
// import com.alibaba.druid.sql.ast.SQLExprImpl;
// import com.alibaba.druid.sql.ast.SQLObject;
// import com.alibaba.druid.sql.ast.SQLReplaceable;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.util.ArrayList;
// import java.util.std::shared_ptr<std::list;

#include "SQLArrayExpr.h"
#include "../../visitor/SQLASTVisitor.h"
#include "../SQLExpr.h"
#include "../SQLObject.h"
#include "../../../utils/listAddAll.h"
#include "../../../utils/ifeq.h"

SQLArrayExpr::SQLArrayExpr()
{
  values = std::make_shared<std::list<SQLExpr_ptr>>();
}

SQLObject_ptr SQLArrayExpr::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLArrayExpr>(new SQLArrayExpr());
  std::shared_ptr<SQLArrayExpr> x = std::dynamic_pointer_cast<SQLArrayExpr>(clone_tmp);
  // SQLArrayExpr *x = new SQLArrayExpr();
  if (expr != nullptr)
  {
    x->setExpr(std::dynamic_pointer_cast<SQLExpr>(expr->clone()));
  }
  for (SQLExpr_ptr value : *values)
  {
    SQLExpr_ptr value2 = std::dynamic_pointer_cast<SQLExpr>(value->clone());
    value2->setParent(x);
    x->values->push_back(value2);
  }
  return x;
}

SQLExpr_ptr SQLArrayExpr::getExpr()
{
  return expr;
}

void SQLArrayExpr::setExpr(SQLExpr_ptr expr)
{
  this->expr = expr;
}

SQLExpr_list_ptr SQLArrayExpr::getValues()
{
  return values;
}

void SQLArrayExpr::setValues(SQLExpr_list_ptr values)
{
  this->values = values;
  if (values != nullptr)
  {
    for (SQLExpr_ptr value : *values)
    {
      value->setParent(SharedObject(SQLArrayExpr));
    }
  }
}

//@Override
void SQLArrayExpr::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLArrayExpr)))
  {
    if (expr != nullptr)
    {
      this->expr->accept(visitor);
    }

    if (values != nullptr)
    {
      for (SQLExpr_ptr value : *values)
      {
        if (value != nullptr)
        {
          value->accept(visitor);
        }
      }
    }
  }
  visitor->endVisit(SharedObject(SQLArrayExpr));
}

SQLObject_list_ptr SQLArrayExpr::getChildren()
{
  SQLObject_list_ptr children = std::make_shared<std::list<SQLObject_ptr>>();
  children->push_back(this->expr);
  // children.addAll(this->values);
  Utils::ListAddAll<SQLExpr, SQLObject>(this->values, children);
  return children;
}

//@Override
int SQLArrayExpr::hashCode()
{
  int prime = 31;
  int result = 1;
  result = prime * result + ((expr == nullptr) ? 0 : expr->hashCode());
  // result = prime * result + ((values == nullptr) ? 0 : values->hashCode());
  return result;
}

//@Override
bool SQLArrayExpr::equals(Object_ptr obj)
{
  if (this == obj.get())
  {
    return true;
  }
  if (obj == nullptr)
  {
    return false;
  }
  if (getClass() != obj->getClass())
  {
    return false;
  }
  std::shared_ptr<SQLArrayExpr> other = std::dynamic_pointer_cast<SQLArrayExpr>(obj);
  if (expr == nullptr)
  {
    if (other->expr != nullptr)
    {
      return false;
    }
  }
  else if (!expr->equals(other->expr))
  {
    return false;
  }
  if (values == nullptr)
  {
    if (other->values != nullptr)
    {
      return false;
    }
  }
  else if (!IFEQ::ifeq<SQLExpr_ptr>(values, other->values))
  {
    return false;
  }
  return true;
}

//@Override
BOOL_ptr SQLArrayExpr::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  auto it_values = values->begin();
  for (int i = 0; i < values->size(); i++)
  {
    std::advance(it_values, i);
    if ((*it_values) == expr)
    {
      target->setParent(SharedObject(SQLArrayExpr));
      (*it_values) = target;
      return BOOL::TRUE;
    }
  }
  return BOOL::FALSE;
}
